﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RconLibrary.Protocol
{
    /// <summary>
    /// Data reading helper class.
    /// </summary>
    public class DataReader : IDisposable
    {
        /// <summary>
        /// Buffer contents.
        /// </summary>
        private byte[] buffer;

        /// <summary>
        /// Stores the current buffer position.
        /// </summary>
        private int position = 0;

        /// <summary>
        /// Gets the current read position.
        /// </summary>
        public int Position
        {
            get
            {
                return position;
            }
        }

        /// <summary>
        /// Data converter.
        /// </summary>
        private DataHelper converter = new DataHelper();

        /// <summary>
        /// Creates a new reader instance.
        /// </summary>
        /// <param name="data">Data buffer.</param>
        public DataReader(ref byte[] data)
        {
            this.converter.IsLittleEndian = true;
            this.buffer = data;
            this.position = 0;
        }

        /// <summary>
        /// Reads a set of bytes.
        /// </summary>
        /// <param name="bytes">Number of bytes to be read.</param>
        /// <returns></returns>
        public byte[] ReadBytes(int bytes)
        {
            byte[] retn = new byte[bytes];
            if (this.CheckLength(bytes))
            {
                for (int i = 0; i < bytes; i++)
                {
                    retn[i] = this.ReadByte();
                }
            }
            return retn;
        }

        /// <summary>
        /// Reads a byte from the buffer.
        /// </summary>
        /// <returns></returns>
        public char ReadChar()
        {
            if (this.CheckLength(1))
            {
                return (char) this.buffer[this.position++];
            }
            else
            {
                return '\0';
            }
        }

        /// <summary>
        /// Reads a short from the buffer.
        /// </summary>
        /// <returns></returns>
        public short ReadShort()
        {
            if (this.CheckLength(2))
            {
                int pos = this.position;
                this.position += 2;
                return this.converter.ToInt16(this.buffer.Slice(pos, 2), 0);
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Reads an int from the buffer.
        /// </summary>
        /// <returns></returns>
        public int ReadInt()
        {
            if (this.CheckLength(4))
            {
                int pos = this.position;
                this.position += 4;
                return this.converter.ToInt32(this.buffer.Slice(pos, 4), 0);
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Reads a byte from the buffer.
        /// </summary>
        /// <returns></returns>
        public byte ReadByte()
        {
            if (this.CheckLength(1))
            {
                return this.buffer[this.position++];
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Reads a short from the buffer.
        /// </summary>
        /// <returns></returns>
        [CLSCompliant(false)]
        public ushort ReadUShort()
        {
            if (this.CheckLength(2))
            {
                int pos = this.position;
                this.position += 2;
                return this.converter.ToUInt16(this.buffer.Slice(pos, 2), 0);
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Reads an int from the buffer.
        /// </summary>
        /// <returns></returns>
        [CLSCompliant(false)]
        public uint ReadUInt()
        {
            if (this.CheckLength(4))
            {
                int pos = this.position;
                this.position += 4;
                return this.converter.ToUInt32(this.buffer.Slice(pos, 4), 0);
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Checks if the reader can read the current ammount of data.
        /// </summary>
        /// <param name="bytes">Number of required bytes.</param>
        /// <returns></returns>
        private bool CheckLength(int bytes)
        {
            return (this.position + bytes) < this.buffer.Length;
        }

        /// <summary>
        /// Disposes the current object.
        /// </summary>
        public void Dispose()
        {
        }

    }

}
